package org.stvd.controller;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.oauth2.common.util.OAuth2Utils;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.stvd.common.security.SecurityUserHolder;
import org.stvd.common.utils.InterfaceResult;
import org.stvd.common.utils.encode.RSAUtil;
import org.stvd.core.util.StringUtil;
import org.stvd.service.oauth.OauthClientDetailsService;

/**
 * @Title OauthSignInController
 * @Describtion 授权登录控制类
 * @author houzx
 * @date 2021年6月11日
 */
@Controller
public class OauthSignInController {

    @Autowired
    private OauthClientDetailsService oauthClientDetailsService;
    
    //获取授权地址
    private final String OAUTH2_AUTHORIZE_URL = "oauth/authorize";
    //是否强制用户重新登录，true：是，false：否。默认true
    private final String OAUTH2_AUTHORIZE_FORCE_LOGIN = "forcelogin";
    //授权参数信息Session存储标识
    private final String OAUTH2_AUTHORIZE_SESSION_NAME = "ausp";
    
    private String returnURL = "/Signin.html";
    
    /**
     * 系统登录请求
     * @param map
     * @param request
     * @return
     */
    @GetMapping(value = "signin")
    public String onLoginLoad(ModelMap map, HttpServletRequest request, @RequestParam Map<String, String> parameters) {
        //判断是否返回错误
        String error = request.getParameter("error");
        if(!StringUtil.isEmpty(error) && "params_error".equals(error)) {
            map.put("errorMsg", request.getParameter("error_description"));
            return returnURL;
        }
        if(!parameters.containsKey(OAuth2Utils.CLIENT_ID) || !parameters.containsKey(OAuth2Utils.REDIRECT_URI)){
            map.put("errorMsg", "请求不合法, client_id、redirect_uri参数异常！");
            return returnURL;
        }
        if(!oauthClientDetailsService.hasOauthClientId(parameters.get(OAuth2Utils.CLIENT_ID))) {
            map.put("errorMsg", "client_id是无效的、过期的或已撤销的！");
            return returnURL;
        }
        if(!oauthClientDetailsService.hasOauthRedirectUri(parameters.get(OAuth2Utils.CLIENT_ID), parameters.get(OAuth2Utils.REDIRECT_URI))) {
            map.put("errorMsg", "redirect_uri不匹配！");
            return returnURL;
        }
        if(SecurityUserHolder.getCurrentUserDetail()!=null
                && parameters.containsKey(OAUTH2_AUTHORIZE_FORCE_LOGIN) 
                && "false".equals(parameters.get(OAUTH2_AUTHORIZE_FORCE_LOGIN))) {
            return "redirect:" + getOauth2AuthorizeUrl(parameters);
        }
        try {
            HttpSession session = request.getSession();
            session.setAttribute(OAUTH2_AUTHORIZE_SESSION_NAME, Base64.getEncoder().encodeToString(getOauth2AuthorizeUrl(parameters).getBytes("utf-8")));
            String path = this.getClass().getResource("/rsakey/publicKey.txt").getFile();
            String publicKey = RSAUtil.readTxt(path);
            map.put("publicKey", publicKey);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            map.put("errorMsg", e.getMessage());
        }
        return returnURL;
    }
    

    private String getOauth2AuthorizeUrl(Map<String, String> paramsMap) {
        try {
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append(OAUTH2_AUTHORIZE_URL);
            stringBuilder.append("?response_type=code");
            stringBuilder.append("&client_id=");
            stringBuilder.append(paramsMap.get(OAuth2Utils.CLIENT_ID));
            stringBuilder.append("&redirect_uri=");
            stringBuilder.append(URLEncoder.encode(paramsMap.get(OAuth2Utils.REDIRECT_URI),"utf-8"));
            if(paramsMap.containsKey(OAuth2Utils.SCOPE)) {
                stringBuilder.append("&scope=");
                stringBuilder.append(paramsMap.get(OAuth2Utils.SCOPE));
            }
            if(paramsMap.containsKey(OAuth2Utils.STATE)) {
                stringBuilder.append("&state=");
                stringBuilder.append(paramsMap.get(OAuth2Utils.STATE));
            }
            return stringBuilder.toString();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return OAUTH2_AUTHORIZE_URL;
    }
    
    /**
     * 登录成功
     * @param map
     * @param request
     * @return
     */
    @GetMapping(value = "signin_success")
    @ResponseBody
    public InterfaceResult<Map<String, Object>> loginSuccess(ModelMap map, HttpServletRequest request) {
        InterfaceResult<Map<String, Object>> result = new InterfaceResult<Map<String,Object>>();
        Map<String, Object> returnMap = new HashMap<String, Object>();
        String oauth2AuthorizeRequestUrl = OAUTH2_AUTHORIZE_URL;
        HttpSession session = request.getSession(false);
        if(session != null) {
            String sessionValue = (String) session.getAttribute(OAUTH2_AUTHORIZE_SESSION_NAME);
            if(!StringUtil.isEmpty(sessionValue)) {
                try {
                    oauth2AuthorizeRequestUrl = new String(Base64.getDecoder().decode(sessionValue), "utf-8");
                    session.removeAttribute(OAUTH2_AUTHORIZE_SESSION_NAME);
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
            }
        }
        returnMap.put("redirectUrl", oauth2AuthorizeRequestUrl);
        result.setResult(returnMap);
        result.setMsg("登录成功！");
        return result;
    }
    
    /**
     * 登录失败
     * @param map
     * @param request
     * @return
     */
    @GetMapping(value = "signin_fail")
    @ResponseBody
    public InterfaceResult<Map<String, Object>> loginFail(ModelMap map, HttpServletRequest request) {
        InterfaceResult<Map<String, Object>> result = new InterfaceResult<Map<String,Object>>();
        result.setError("账号或密码错误！");
        HttpSession session = request.getSession(false);
        if (session != null) {
            AuthenticationServiceException authenticationServiceException 
                = (AuthenticationServiceException) session.getAttribute("SPRING_SECURITY_LAST_EXCEPTION");
            if(authenticationServiceException != null) {
                result.setError(authenticationServiceException.getMessage());
            }
        }
        return result;
    }
    
}